package robocode;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;

import controle.dados.Constants;
import controle.dados.Constants.MeuLadoCampo;
import controle.dados.ParametroRedeNeural;
import controle.redeNeural.RNAproximacao;
import controle.redeNeural.RNGenerica;
import controle.redeNeural.RNRetornarMinhaArea;

import robocode.DadosRobos.RoboScaneado;
import Matematica.CalculoVetores;
import Matematica.XY;

public class CalculosRoboCode {
	
	private RNGenerica redeAvanco = new RNAproximacao();
	private RNGenerica redeRetornar = new RNRetornarMinhaArea();
	private int _countSalvarRefem = 0;
	
	
	
	public List<String> getOrdensSalvarRefem(RoboScaneado robo, RoboScaneado refemSalvar,
			List<RoboScaneado> robosScaneados){
		List<String> ordens = new ArrayList<String>();
		
		System.out.println("Salvando refém...");
		
		//O primeiro campo é o robô do nosso time e o segundo o do adversário

		if (_countSalvarRefem%2 == 0) {
			//retreinar...
			//desejadosSalvarRefem --> � o que tinha
			//comparar com o que eu obtive
			//robo.getX()
			//robo.getY()
			//calculo erro
			//chamo o retreinar...
			double erroX = Math.abs(refemSalvar.getX() - robo.getX());
			double erroY = Math.abs(refemSalvar.getY() - robo.getY());
			if (erroX >= 200 || erroY >= 200) {
				redeRetornar.treinarNovamente();//retreinar
				System.out.println("## Treinar novamente");
			}
		}
		
		ParametroRedeNeural parametroRN = new ParametroRedeNeural(robosScaneados);
		XY[] posicoesDeslocar = redeAvanco.executar(parametroRN);
		
		_countSalvarRefem++;
		
		for(XY posicaoDeslocar : posicoesDeslocar)
		{
			if (posicaoDeslocar==null) { continue;}
			double qtdVirar = CalculoVetores.getQuantidadeVirar(robo.getX(), robo.getY(), posicaoDeslocar.X(),
					posicaoDeslocar.Y(), robo.getHeading());
			addOrdemVirar(ordens, qtdVirar);
			
			double distancia = CalculoVetores.distanciaPontos(robo.getX(), robo.getY(), posicaoDeslocar.X(),
					posicaoDeslocar.Y());
			addOrdemAndar(ordens, distancia);
		}
		
		double qtdVirar = CalculoVetores.getQuantidadeVirar(robo, refemSalvar);
		addOrdemAndar(ordens, qtdVirar);
		
		double distancia = CalculoVetores.distanciaPontos(robo.getX(),robo.getY(),refemSalvar.getX(),
				refemSalvar.getY());
		
		addOrdemAndar(ordens, distancia);
		
		return ordens;
	}
	
	public List<String> getOrdensVoltarMinhaArea(RoboScaneado robo, List<RoboScaneado> robosAdversarios, double posXF, double posYF) {
		List<String> ordens = new ArrayList<String>();
			
		ParametroRedeNeural parametroRN = new ParametroRedeNeural(robosAdversarios);
		
		System.out.println("Retornando...");
		
		XY[] posicoesDeslocar = redeRetornar.executar(parametroRN);
		
		for(XY posicaoDeslocar : posicoesDeslocar)
		{
			if(posicoesDeslocar == null)
				continue;

			double qtdVirar = CalculoVetores.getQuantidadeVirar(robo.getX(), robo.getY(), posicaoDeslocar.X(),
					posicaoDeslocar.Y(), robo.getHeading());
			addOrdemVirar(ordens, qtdVirar);
			
			double distancia = CalculoVetores.distanciaPontos(robo.getX(), robo.getY(), posicaoDeslocar.X(),
					posicaoDeslocar.Y());
			addOrdemAndar(ordens, distancia);
		}

		double qtdVirar = CalculoVetores.getQuantidadeVirar(robo.getX(), robo.getY(), posXF, posYF, robo.getHeading());
		addOrdemVirar(ordens, qtdVirar);
		
		double distancia = CalculoVetores.distanciaPontos(robo.getX(), robo.getY(), posXF, posYF);
		addOrdemAndar(ordens, distancia);
		return ordens;
	}
	
	public List<String> getOrdensRefemSeguirRoboSalvador(RoboScaneado robo, RoboScaneado refemSalvar) {
		List<String> ordens = new ArrayList<String>();
		double qtdVirar = CalculoVetores.getQuantidadeVirar(refemSalvar, robo);
		double distancia = getDistanciaRobos(refemSalvar, robo);
		double vlrSeguir = 0.0;

		if (distancia > 100) {
			vlrSeguir = distancia - 50.0;
		} else {
			if (distancia > 60.0) {
				vlrSeguir = 40.0;
			} else {
				vlrSeguir = -30.0; // d� a r�
			}
		}
		
		if (Math.abs(vlrSeguir) > 0.0) {
			addOrdemVirar(ordens, qtdVirar);
			addOrdemAndar(ordens, vlrSeguir);
		}
		
		return ordens;
	}

	public List<String> getOrdensAProximarRoboPrender(RoboScaneado robo, RoboScaneado refemPrender
			,List<RoboScaneado> robosInimigos) {
		List<String> ordens = new ArrayList<String>();
		
		ParametroRedeNeural parametroRedeNeural = new ParametroRedeNeural(robosInimigos);
		
		double qtdVirar = CalculoVetores.getQuantidadeVirar(robo, refemPrender);
		addOrdemVirar(ordens, qtdVirar);		
		
		double distancia = getDistanciaRobos(robo, refemPrender);
		addOrdemAndar(ordens, distancia);
		
		return ordens;
	}
	
	public List<String> getOrdensAtacar(RoboScaneado robo, RoboScaneado rinimigo) {
		List<String> ordens = new ArrayList<String>();
		double qtdVirar = CalculoVetores.getQuantidadeVirar(robo, rinimigo);
		addOrdemVirar(ordens, qtdVirar);
		
		double distancia = getDistanciaRobos(robo, rinimigo);
		addOrdemAndar(ordens, distancia);
		return ordens;
	}
	
	public List<String> getOrdensBloquearAgSave(RoboScaneado robo, RoboScaneado rinimigo) {
		List<String> ordens = new ArrayList<String>();
		
		double qtdVirar = CalculoVetores.getQuantidadeVirar(rinimigo, robo);
		addOrdemVirar(ordens, qtdVirar);
		
		double distancia = getDistanciaRobos(rinimigo, robo);
		addOrdemAndar(ordens, distancia);
		return ordens;
	}
	
//	public List<String> getOrdensLudibriarInimigo(int idRobo){
////		List<String> ordens = new ArrayList<String>();
////		
////		double xRefem = _imj.getR2().getX();
////    	double yI = _imj.getR3().getY();
////    	double Ysalvador = _imj.getR1().getY();
////        if (yI <= 200) { //por baixo
////        	Ysalvador+=100;
////        } else { //por cima
////        	Ysalvador-=100;
////        }
////
////		double qtdVirar = CalculoVetores.getQuantidadeVirar(
////							_imj.getR1().getX(), _imj.getR1().getY(),  
////							xRefem, Ysalvador, _imj.getR1().getHeading()
////							);
////		addOrdemVirar(ordens, qtdVirar);
////		
////		ordens.add("5");
////		double distancia = getDistanciaInimigo();
////		
////		//System.out.println("distancia: " + distancia);
////		if (distancia <= 50) {
////			ordens.add(distancia + "");
////		}  else {
////			
////			if (distancia > 100) {
////				ordens.add((distancia-50.0) + "");
////			} else {
////				ordens.add(50 + "");
////			}
////		}
////		return ordens;
//		
//		return getOrdensSalvarRefem(idRobo); //por enquanto....
//	}
	
	public boolean VolteiMinhaAreaPessoal(RoboScaneado rb, MeuLadoCampo mlc, double wCampo, double hCampo){
		return VolteiMinhaAreaPessoal(rb.getX(), rb.getY(), mlc, wCampo, hCampo);
	}
	
	public boolean VolteiMinhaAreaPessoal(double x, double y, MeuLadoCampo mlc, double wCampo, double hCampo){
		switch (mlc) {
			case Baixo: if (y >= hCampo/2) return true;
			case Topo:  if (y <= hCampo/2) return true;
			case Esquerda: if (x >= wCampo/2) return true;
			case Direita: if (x <= wCampo/2) return true;
		}
		return false;
	}
	
	public double getXFinalRobo(MeuLadoCampo mlc, double wCampo, double hCampo){
		double dR = new Random().nextDouble()*125D;
		switch (mlc) {
			case Baixo: 
			case Topo:  return 0 + dR;
			case Esquerda: return (wCampo/2) + dR;
			case Direita: return 0 + dR;
		}
    	return 0.0D;
    }
	public double getYFinalRobo(MeuLadoCampo mlc, double wCampo, double hCampo){
		double dR = new Random().nextDouble()*125D;
		switch (mlc) {
			case Baixo: return (hCampo/2) + dR;
			case Topo:  return 0 + dR;
			case Esquerda:
			case Direita: return 0 + dR;
		}
		return 0.0D;
    }
	
	//############################################################
	public double getDistanciaRobos(RoboScaneado rb1, RoboScaneado rb2){
		if (rb1 == null || rb2 == null) {return 0;}
		return CalculoVetores.distanciaPontos(rb1.getX(), rb1.getY(),rb2.getX(), rb2.getY());
	} 
	
	private void addOrdemVirar(List<String> ordens, double qtdVirar){
		if (
				!Matematica.CalculoVetores.Entre(qtdVirar, 0, 1.0) && 
				!Matematica.CalculoVetores.Entre(qtdVirar, 360, 1.0)
			) {
			ordens.add("3"); //virar esquerda
			ordens.add(""+ qtdVirar);
		}
	}
	
	private void addOrdemAndar(List<String> ordens, double distancia){
		ordens.add("5"); //andar
		if (distancia <= 50) {
			ordens.add(distancia + "");
		}  else {
			if (distancia > 100) {
				ordens.add((distancia-50.0) + "");
			} else {
				ordens.add(50 + "");
			}
		}
	}
	
	//---------------------
	
	
}
